package me.zhangsanfeng.gpss.common.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import me.zhangsanfeng.gpss.common.entity.JwtProperty;
import me.zhangsanfeng.gpss.common.handler.LoginFailureHandler;
import me.zhangsanfeng.gpss.common.handler.LoginSuccessHandler;
import me.zhangsanfeng.gpss.common.utils.JsonUtil;
import me.zhangsanfeng.gpss.common.utils.JwtUtil;
import me.zhangsanfeng.gpss.common.utils.ResultUtil;
import me.zhangsanfeng.gpss.entity.Users;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @ClassName:JWTLoginFilter
 * @Description:处理登录，验证用户名密码正确后，生成一个token，并将token返回给客户端。
 * @Author:ZhangYao
 * @Date:2018/11/5 22:05
 * @Version:1.0
 */
@Slf4j
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;

    private JwtProperty jwtProperty;

    public JWTLoginFilter(AuthenticationManager authenticationManager,JwtProperty jwtProperty) {
        this.authenticationManager = authenticationManager;
        this.jwtProperty = jwtProperty;
        setAuthenticationSuccessHandler(new LoginSuccessHandler(jwtProperty));
        setAuthenticationFailureHandler(new LoginFailureHandler());
    }

    // 接收登录信息，并将其封装成UsernamePasswordAuthenticationToken
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        try {
            //将请求中的username、password、authorities等封装成UsernamePasswordAuthenticationToken对象
            Users user = new ObjectMapper().readValue(request.getInputStream(), Users.class);
            log.info("登录信息username：{}",user.getUsername());
            log.info("登录信息password：{}",user.getPassword());
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                    user.getUsername(),
                    user.getPassword(),
                    user.getAuthorities());
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            return authenticate;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

     //用户成功登录后，这个方法会被调用，生成token
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        String username = ((Users) authResult.getPrincipal()).getUsername();
        String token = JwtUtil.createToken(username, jwtProperty);
        response.addHeader("Authorization","Bearer " + token);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        log.info("登录成功！token结果为：{}",token);
        super.successfulAuthentication(request, response, chain, authResult);
    }

    //登录失败后会调用此方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response,
                                              AuthenticationException failed) throws IOException, ServletException {
        log.info("登录失败！原因：",failed);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(JsonUtil.toJsonString(ResultUtil.loginfailure(failed)));
        super.unsuccessfulAuthentication(request, response, failed);
    }
}
